package internal

import (
	"CaptchaCluster/defineMsg"
	"CaptchaCluster/server/conf"
	"CaptchaCluster/server/game/nginx"
	"sync"
	"time"
)

type MachineData struct {
	Pong        chan bool
	Name        string
	Addrr       string
	MachineInfo []defineMsg.ReqMachineInfo
	mutext      sync.Mutex
}

func (m *MachineData) Put(info defineMsg.ReqMachineInfo) {
	m.mutext.Unlock()
	defer m.mutext.Unlock()
	m.MachineInfo = append(m.MachineInfo, info)
}

func (m *MachineData) Pop() []defineMsg.ReqMachineInfo {
	m.mutext.Lock()
	defer m.mutext.Unlock()

	dst := make([]defineMsg.ReqMachineInfo, len(m.MachineInfo))
	copy(dst, m.MachineInfo)

	m.MachineInfo = make([]defineMsg.ReqMachineInfo, 0)
	return dst
}

func (m *MachineData) Enter() {
	go reloadNginx()
}

func (m *MachineData) Quit() {
	go reloadNginx()
}

var t *time.Timer
var mutex sync.Mutex

func reloadNginx() {
	mutex.Lock()
	defer mutex.Unlock()

	if t != nil {
		t.Stop()
	}

	nginxConf := arithmeticWeight()
	if len(nginxConf) == 0 {
		return
	}

	nginx.WriteConf(nginxConf)
	nginx.Reload()

	t = time.AfterFunc(time.Duration(conf.Server.Nginx.ReloadTimes)*time.Minute, reloadNginx)
}

// 返回切片中,MachineInfo[0].CPUPercent为计算后的权重
func arithmeticWeight() []nginx.NginxConf {
	var balanceInfo []MachineData

	conns.Range(func(_, value interface{}) bool {
		client := value.(*MachineData)

		var (
			kernel int
			cpu    float64
			mem    float64
		)

		var count float64
		for _, v := range client.Pop() {
			kernel = v.CPUKernel
			cpu += v.CPUPercent
			mem += v.MemPercent
			count++
		}

		data := MachineData{
			Addrr: client.Addrr,
			MachineInfo: []defineMsg.ReqMachineInfo{{
				CPUKernel:  kernel,
				CPUPercent: cpu / count,
				MemPercent: mem / count,
			}},
		}

		balanceInfo = append(balanceInfo, data)
		return true
	})

	// 权重算法
	// CPU核心数 权重30%
	// CPU占用率 权重50%
	// 内存占用率 权重20%
	nginxConf := make([]nginx.NginxConf, len(balanceInfo))
	if len(balanceInfo) > 0 {
		for i, _ := range balanceInfo {
			var (
				kernel float64
				cpu    float64
				mem    float64
			)
			kernel = float64(balanceInfo[i].MachineInfo[0].CPUKernel)
			cpu = balanceInfo[i].MachineInfo[0].CPUPercent
			mem = balanceInfo[i].MachineInfo[0].MemPercent

			weight := int(0.3*kernel + 0.5*(100-cpu) + 0.2*(100-mem))
			nginxConf[i].Addr = balanceInfo[i].Addrr
			if weight < 1 {
				weight = 1
			}
			nginxConf[i].Weight = weight
		}
		return nginxConf
	}
	return nil
}
